package demo.cleancode;

import demo.cleancode.model.UserQuery;
import demo.cleancode.model.UserVO;
import demo.entity.UserDO;
import demo.enums.StatusEnum;
import demo.exception.BizAssert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

/**
 * @author meilin.huang
 * @date 2022-03-23 11:08
 */
public class Demo1 {

    public void bad(UserDO user) {
        if (Objects.equals(user.getStatus(), StatusEnum.ENABLE.getValue())) {
            if (user.getCreatorId() != null) {
                for (String order : user.getOrders()) {
                    if ("1".equals(order)) {
                        System.out.println("获取订单为1，继续执行其他逻辑...");
                    }
                }
            } else {
                System.out.println("创建者为空...继续执行其他逻辑");
            }
        } else {
            throw BizAssert.newException("该用户不为可用状态，无法操作");
        }
    }

    public void good(UserDO user) {
        BizAssert.equals(user.getStatus(), StatusEnum.ENABLE.getValue(), "该用户不为可用状态，无法操作");
        if (user.getCreatorId() == null) {
            System.out.println("创建者为空...继续执行其他逻辑");
            return;
        }
        for (String order : user.getOrders()) {
            if (!"1".equals(order)) {
                continue;
            }
            System.out.println("获取订单为1，继续执行其他逻辑...");
        }
    }

    public void bad1(UserDO user) {
        if (Objects.equals(user.getStatus(), StatusEnum.ENABLE.getValue())) {
            //此时若还有其他if for等逻辑，代码层次就会多一层
            System.out.println("执行其他一堆业务逻辑...");
        }
        throw BizAssert.newException("该用户不为可用状态，无法操作");
    }


    public void good1(UserDO user) {
        // 提前校验是否符合业务逻辑，不符合则抛异常终止后续逻辑。减少真正业务逻辑的代码层级
        if (!Objects.equals(user.getStatus(), StatusEnum.ENABLE.getValue())) {
            throw BizAssert.newException("该用户不为可用状态，无法操作");
        }
        System.out.println("执行其他一堆业务逻辑...");
        // ........
    }


    public void veryGood1(UserDO user) {
        // 类似的逻辑判断，使用业务断言效果最佳
        BizAssert.equals(user.getStatus(), StatusEnum.ENABLE.getValue(), "该用户不为可用状态，无法操作");
        System.out.println("执行其他一堆业务逻辑...");
    }


    public int bad2(UserDO user) {
        int result;
        // 大量if-else判断
        if (Objects.equals(user.getStatus(), StatusEnum.ENABLE.getValue())) {
            result = 1;
        } else if (Objects.equals(user.getStatus(), StatusEnum.DISABLE.getValue())) {
            result = 2;
        } else {
            result = 3;
        }
        return result;
    }


    public int good2(UserDO user) {
        // 使用卫语句，提前return，避免申明临时变量result以及不必要的else代码块。减少代码层级
        if (Objects.equals(user.getStatus(), StatusEnum.ENABLE.getValue())) {
            return 1;
        }
        if (Objects.equals(user.getStatus(), StatusEnum.DISABLE.getValue())) {
            return 2;
        }
        return 3;
    }


    public void bad3(List<UserDO> users) {
        for (UserDO user : users) {
            // 此时若还有其他if for等逻辑，代码层次就会多一层
            if (Objects.equals(user.getStatus(), StatusEnum.ENABLE.getValue())) {
                System.out.println("执行其他一堆业务逻辑...");
            }
        }
    }


    public void good3(List<UserDO> users) {
        for (UserDO user : users) {
            // 提前跳过不符合业务逻辑的遍历。减少需要执行的业务代码层级
            if (!Objects.equals(user.getStatus(), StatusEnum.ENABLE.getValue())) {
                continue;
            }
            System.out.println("执行其他一堆业务逻辑...");
        }
    }


    private UserService userService;

    @GetMapping("/users")
    public List<UserVO> badQuery1(@RequestParam(required = false) String username,
                                  @RequestParam(required = false) Integer status,
                                  @RequestParam(required = false) Integer pageNum,
                                  @RequestParam(required = false) Integer pageSize) {
        // 后续新增查询字段时，要改的地方太多
        return userService.listByQuery2(username, status, pageNum, pageSize);
    }

    @GetMapping("/users")
    public List<UserVO> badQuery2(@RequestParam(required = false) String username,
                                  @RequestParam(required = false) Integer status,
                                  @RequestParam(required = false) Integer pageNum,
                                  @RequestParam(required = false) Integer pageSize) {
        // 需要手动赋值到query对象，后续增加字段还要加入参，但比第一种方便些
        UserQuery query = new UserQuery().setUsername(username).setStatus(status);
        query.setPageNum(pageNum);
        query.setPageSize(pageSize);
        return userService.listByQuery(query);
    }

    @GetMapping("/users")
    public List<UserVO> query(UserQuery userQuery) {
        // 加字段等，只需要在UserQuery里加即可，所有方法形参无需改动
        return userService.listByQuery(userQuery);
    }


    public boolean isEnabledBad(UserDO user) {
        // 不记录日志，且没有其他用途的局部变量不要多余声明，且idea也给出了黄色警告
        boolean isEnabled = Objects.equals(user.getStatus(), StatusEnum.ENABLE.getValue());
        return isEnabled;
    }


    public boolean isEnabledGood(UserDO user) {
        return Objects.equals(user.getStatus(), StatusEnum.ENABLE.getValue());
    }


    public void badVar() {
        LoginAccount la = LoginAccount.getFromContext();
        // 1.虽然代码量更少，但是需要多调用两次相同的方法(根据具体方法内部调用情况虚拟机栈可能会多许多栈帧的出入)
        // 2.假如是其他场景值，后续根据业务需求需要变更对应值的内容，则需要修改多处
        UserDO user = new UserDO()
                .setCreatorId(la.getId())
                .setModifierId(la.getId())
                .setCreateTime(LocalDateTime.now())
                .setUpdateTime(LocalDateTime.now());
        userService.save(user);
    }


    public void goodVar() {
        LoginAccount la = LoginAccount.getFromContext();
        // 存储于局部变量，减少栈帧出入，也方便统一修改
        Long accountId = la.getId();
        LocalDateTime now = LocalDateTime.now();
        UserDO user = new UserDO()
                .setCreatorId(accountId)
                .setModifierId(accountId)
                .setCreateTime(now)
                .setUpdateTime(now);
        userService.save(user);
    }


}
